﻿#region Copyright (c) 2011, thinktecture (http://www.thinktecture.com)

/*
   thinktecture.UIAnnotations was developed by Jörg Neumann.
   Copyright (c) 2011, thinktecture (http://www.thinktecture.com).
   All rights reserved, comes as-is and without any warranty. Use of this
   source file is governed by the license which is contained in LICENSE.TXT 
   in the distribution.
*/

#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;
using System.Reflection;

namespace Thinktecture.DataForm
{
    internal static class BindingHelpers
    {
        public static void ChangeBinding(FrameworkElement element, DependencyProperty dp, Action<Binding> action)
        {
            Binding bind = BindingOperations.GetBinding(element, dp);
            Binding newBinding = new Binding()
            {
                AsyncState = bind.AsyncState,
                BindingGroupName = bind.BindingGroupName,
                BindsDirectlyToSource = bind.BindsDirectlyToSource,
                Converter = bind.Converter,
                ConverterCulture = bind.ConverterCulture,
                ConverterParameter = bind.ConverterParameter,
                FallbackValue = bind.FallbackValue,
                IsAsync = bind.IsAsync,
                Mode = bind.Mode,
                NotifyOnSourceUpdated = bind.NotifyOnSourceUpdated,
                NotifyOnTargetUpdated = bind.NotifyOnTargetUpdated,
                NotifyOnValidationError = bind.NotifyOnValidationError,
                Path = bind.Path,
                Source = (bind.Source == null) ? element.GetValue(FrameworkElement.DataContextProperty) : bind.Source,
                StringFormat = bind.StringFormat,
                TargetNullValue = bind.TargetNullValue,
                UpdateSourceExceptionFilter = bind.UpdateSourceExceptionFilter,
                UpdateSourceTrigger = bind.UpdateSourceTrigger,
                ValidatesOnDataErrors = bind.ValidatesOnDataErrors,
                ValidatesOnExceptions = bind.ValidatesOnExceptions,
                XPath = bind.XPath
            };
            bind.ValidationRules.ToList().ForEach(rule => { bind.ValidationRules.Remove(rule); newBinding.ValidationRules.Add(rule); });
            action(newBinding);
            BindingOperations.ClearBinding(element, dp);
            BindingOperations.SetBinding(element, dp, newBinding);
        }

        public static object GetRealBindingSource(BindingExpression expression, object source, out string path)
        {
            path = string.Empty;
            if (source != null &&
                expression != null &&
                expression.ParentBinding != null &&
                expression.ParentBinding.Path != null &&
                string.IsNullOrEmpty(expression.ParentBinding.Path.Path) == false &&
                expression.ParentBinding.Path.Path.IndexOf('.') > 0)
            {
                path = expression.ParentBinding.Path.Path;
                string[] props = expression.ParentBinding.Path.Path.Split('.');
                object currentObject = source;
                if (props.Length > 1)
                {
                    path = props[props.Length - 1];
                    for (int i = 0; i < props.Length - 1; i++)
                    {
                        PropertyInfo property = currentObject.GetType().GetProperty(props[i]);
                        if (property == null)
                        {
                            currentObject = null;
                            break;
                        }
                        currentObject = property.GetValue(currentObject, null);
                        if (currentObject == null)
                        {
                            break;
                        }
                    }
                }
                return currentObject;
            }
            else if (expression != null &&
                expression.ParentBinding != null &&
                expression.ParentBinding.Path != null)
            {
                path = expression.ParentBinding.Path.Path;
            }
            return source;
        }
    }
}
